package main

import (
	"crypto/sha1"
	"fmt"
	"github.com/satori/go.uuid"
	"reflect"
	"strings"
	"time"
	"unsafe"
)

type PacketHeader struct {
	Magic         int16
	Version       int32
	OperationType int32
	ContentSize   int32
}

type SignBody struct {
	UUID      string
	Timestamp int64
	Sign      string
}

type HostConnBody struct {
	HostName string
	SignBody
}

type LineConnBody struct {
	HostName string
	LineNum  int32
	SignBody
}

type LineCallBody struct {
	LineNum       int32
	Network       string
	ProxyPort     uint16
	TargetAddress string
	SignBody
}

const PacketHeaderSize = int(unsafe.Sizeof(PacketHeader{}))

const PacketMagic = int16(0xCA)
const PacketVersion = 0x10000

const OptTypeHostConn = 0x1
const OptTypeLineConn = 0x2
const OptTypeHostSyn = 0x3

const OptTypeHostAck = 0x101
const OptTypeLineCall = 0x102

func StructToBytes(pointer unsafe.Pointer, size int) []byte {
	var header reflect.SliceHeader
	header.Len = size
	header.Cap = size
	header.Data = uintptr(pointer)
	return *(*[]byte)(unsafe.Pointer(&header))
}

func BytesToStruct(bytes []byte) unsafe.Pointer {
	return unsafe.Pointer(((*reflect.SliceHeader)(unsafe.Pointer(&bytes))).Data)
}

func (sign *SignBody) GenerateSign(secretKey string) {
	sign.UUID = uuid.NewV4().String()
	sign.Timestamp = time.Now().UnixNano() / int64(time.Millisecond)
	content := fmt.Sprintf("%s%s%d", sign.UUID, secretKey, sign.Timestamp)
	sign.Sign = fmt.Sprintf("%x", sha1.Sum([]byte(content)))
}

func (sign *SignBody) CheckSign(secretKey string) bool {
	content := fmt.Sprintf("%s%s%d", sign.UUID, secretKey, sign.Timestamp)
	checkSign := fmt.Sprintf("%x", sha1.Sum([]byte(content)))
	return strings.Compare(checkSign, sign.Sign) == 0
}

func (sign *SignBody) CheckTimestamp(timeout time.Duration) bool {
	timestamp := sign.Timestamp
	now := time.Now().UnixNano() / int64(time.Millisecond)
	max := now + int64(timeout)
	min := now - int64(timeout)
	if timestamp > max || timestamp < min {
		return false
	}
	return true
}
